/*******************************************************
 * 函数名：ShowIP
 * 描述  ：滑动显示当前设备IP
 * 参数  ：无
 * 返回值：无
 **********************************************************/
void ShowIP()
{
    int sa[4], r=0, t=0;
    String oneLine = WiFi.localIP().toString()+".";
    int s1,s2,s3;
    int ipx,x = 32;
    uint16_t ipcolor=hsv2rgb(hue, saturation, value);
    for (int i=0; i < oneLine.length(); i++)
    { 
      if(oneLine.charAt(i) == '.') 
      { 
        sa[t] = oneLine.substring(r, i).toInt();
        r=(i+1); 
        t++; 
      }
    }
    for(int j=0;j<85;j++){
      ipx = x;
      for(int i=0; i < 4; i++){
        s1 = sa[i]/100;
        s2 = (sa[i] - s1*100)/10;
        s3 = (sa[i] - s1*100)%10;
        if(sa[i]>99){
          showCharacter(ipx, 2, s1 + 48, Clock3x5, ipcolor);
          ipx += 4;
          showCharacter(ipx, 2, s2 + 48, Clock3x5, ipcolor);
          ipx += 4;
          showCharacter(ipx, 2, s3 + 48, Clock3x5, ipcolor);
        }else if(sa[i]>9){
          showCharacter(ipx, 2, s2 + 48, Clock3x5, ipcolor);
          ipx += 4;
          showCharacter(ipx, 2, s3 + 48, Clock3x5, ipcolor);
        }else{
          showCharacter(ipx, 2, s3 + 48, Clock3x5, ipcolor);
        }
        if(i<3){
          ipx += 4;
          matrix.drawPixel(ipx,6,ipcolor);
          ipx += 2;
        }
      }
      if(--x < -90) {
        x = matrix.width();
      }
      matrix.show();
      system_soft_wdt_feed();
      delay(80);
      matrix.clear();
    }
    matrix.clear();
}

void InitServer(){
  // start MDNS
  if (MDNS.begin(MDNS_NAME)) {
    Serial.println("MDNS responder started.");
  }
  // start web server
  // handle index
  server.on("/", []() {
    // send index.html
    server.send(200, "text/html; charset=utf-8", "<!DOCTYPE html><html lang='cn'><head> <link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/picnic'> <script src='https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js'></script> <title>像素时钟</title> <style> span {font-size:150%} label {height:80%} h1 label {margin: 0 auto; text-align: center;} div label {margin: 0 auto; text-align: center;} dev img {margin: 0 auto; text-align: center;} input[type=range] { -webkit-appearance: none; width: 100%; background: -webkit-linear-gradient(#1765db, #1765db) no-repeat, #ddd; height: 3px; } input[type=range]::-webkit-slider-thumb { -webkit-appearance: none; height: 26px; width: 26px; background: #fff; border-radius: 50%; border: solid 1px #ddd; } .range {font-size:150%} .pseudo button{font-weight: 30%;} </style></head><body> <div class='tabs four'> <input id='tab-1' type='radio' name='tabgroupB' checked> <label class='pseudo button toggle' for='tab-1' style='font-size: 3em;'>主页</label> <input id='tab-2' type='radio' name='tabgroupB'> <label class='pseudo button toggle' for='tab-2' style='font-size: 3em;'>模式</label> <input id='tab-3' type='radio' name='tabgroupB'> <label class='pseudo button toggle' for='tab-3' style='font-size: 3em;'>配置</label> <input id='tab-4' type='radio' name='tabgroupB'> <label class='pseudo button toggle' for='tab-4' style='font-size: 3em;'>风格</label> <div class='row'> <div> <h1 class='flex center'>主页</h1> <div class='flex one center'> <div > <img id='emojis' onclick='clickEmoji(event);' style='height: 610px;width: 655px;margin: 0 auto; text-align: center;' src=''>  </div> </div> <h1 id='out' style='margin: 0 auto; text-align: center;'></h1> <div style='margin: 0 auto; text-align: center;'> <canvas id='emoji' width='40' height='40'></canvas> </div> <script> var connection = new WebSocket('ws://' + location.hostname + ':81/', ['arduino']); connection.onopen = function () { connection.send('Connect ' + new Date()); };  connection.onerror = function (error) { console.log('WebSocket Error ', error); };  connection.onmessage = function (e) { console.log('Server: ', e.data);  if(e.data[0]=='{'){ console.log('json'); var jsonOb = eval('('+e.data+')'); var brightNess = typeof(jsonOb.brightNess)=='undefined'? 150:jsonOb.brightNess; var mode = typeof(jsonOb.mode)=='undefined'? 2:jsonOb.mode; var huea = typeof(jsonOb.huea)=='undefined'? 180:jsonOb.huea; var hued = typeof(jsonOb.hued)=='undefined'? 180:jsonOb.hued; var hueh = typeof(jsonOb.hueh)=='undefined'? 180:jsonOb.hueh; var huem = typeof(jsonOb.huem)=='undefined'? 180:jsonOb.huem; var hues = typeof(jsonOb.hues)=='undefined'? 180:jsonOb.hues; var huew = typeof(jsonOb.huew)=='undefined'? 180:jsonOb.huew; var clockMode = typeof(jsonOb.clockMode)=='undefined'? 1:jsonOb.clockMode; var dateMode = typeof(jsonOb.dateMode)=='undefined'? 1:jsonOb.dateMode; $(\"input[name='radio-mode']\").eq(mode-1).attr('checked','checked'); $(\"input[name='radio-clock']\").eq(clockMode-1).attr('checked','checked'); $(\"input[name='radio-date']\").eq(dateMode-1).attr('checked','checked'); document.getElementById('bt').value=parseInt(brightNess); document.getElementById('bt_value').value=parseInt(brightNess); document.getElementById('huea').value=parseInt(huea); document.getElementById('huea_value').value=parseInt(huea); document.getElementById('hued').value=parseInt(hued); document.getElementById('hued_value').value=parseInt(hued); document.getElementById('hueh').value=parseInt(hueh); document.getElementById('hueh_value').value=parseInt(hueh); document.getElementById('huem').value=parseInt(huem); document.getElementById('huem_value').value=parseInt(huem); document.getElementById('hues').value=parseInt(hues); document.getElementById('hues_value').value=parseInt(hues); document.getElementById('huew').value=parseInt(huew); document.getElementById('huew_value').value=parseInt(huew);  } }; function clickEmoji(e) {  var xo = 15; var yo = 15; var xs = 65; var ys = 60; var x = e.offsetX;  var y = e.offsetY; var c = Math.round((x - xo - 20) / xs);  var r = Math.round((y - yo - 20) / ys);  document.getElementById('out').innerText = 'Selected [' + (c + 1) + ', ' + (r + 1) + ']';  var img = document.getElementById('emojis');  var ce = document.getElementById('emoji'); var ctx = ce.getContext('2d');  ctx.drawImage(img, -(xo + (xs * c)), -(yo + (ys * r)), 655, 610);  var index = 'p' + c + '' + r; console.log('index: ' + index);  connection.send(index);  } function FirmwareInfo(){ console.log('FirmwareInfo: F');  connection.send('F'); } </script> <div class='flex one center'> <label> <button class='success' onclick='FirmwareInfo()' style='font-size: 2.5em;right: 0px;'>固件信息</button> </label> </div> </div>  <div> <h1 class='flex center'>模式选择</h1> <div style='height: 800px;'> <h1 class='flex one'> <label> <input type='radio' onclick='changeMode(1);' name='radio-mode'> <span class='checkable'>时钟</span> </label> <br><br> <label> <input type='radio' onclick='changeMode(2);' name='radio-mode'> <span class='checkable'>日期</span> </label> <br><br> <label> <input type='radio' onclick='changeMode(3);' name='radio-mode'> <span class='checkable'>时钟+日期</span> </label> <br><br> <label> <input type='radio' onclick='changeMode(4);' name='radio-mode'> <span class='checkable'>待定</span> </label> <br><br> <label> <input type='radio' onclick='changeMode(5);' name='radio-mode'> <span class='checkable'>代码雨</span> </label> </h1> </div> <br><br> <script> function changeMode(num) {  var modelNum = 'm' + parseInt(num).toString(16);  console.log('Model: ' + modelNum);  connection.send(modelNum); } function nextMode(num) {  var modelNum = 'mc';  console.log('Model: ' + modelNum);  connection.send(modelNum); } </script> <div class='flex two center'> <label> <button class='success' onclick='nextMode()' style='font-size: 2.5em;right: 0px;'>模式Next</button> </label> <label > <label for='tab-1' class='button normal' style='font-size: 2.5em;'>返回主页</label> </label> </div> </div> <div> <h1 class='flex center'>亮度</h1> <div class='range'> <fieldset class='flex three center'> <label style='text-align:right;''><span class='label normal' >亮度</span></label> <label><input id='bt' type='range' min='0' max='255' step='1' oninput='sendBrightness();'/></label>  <label><input id='bt_value' type='text' style='border: 0;' value='125'/> </label> </fieldset> </div> <h1 class='flex center'>颜色</h1> <div class='range'> <fieldset class='flex three center'> <label style='text-align:right;'><span class='label normal' >全局</span></label> <label><input id='huea' type='range' min='0' max='360' step='1' oninput='sendHue(\"a\");' /></label>  <label><input id='huea_value' name='hue_value' type='text' style='border: 0;' value='180'/> </label> </fieldset> </div> <div class='range'> <fieldset class='flex three center'> <label style='text-align:right;'><span class='label normal' >冒号</span></label> <label><input id='hued' type='range' name='hue_value' min='0' max='360' step='1' oninput='sendHue(\"d\");' /></label>  <label><input id='hued_value' name='hue_value' type='text' style='border: 0;' value='180'/> </label> </fieldset> </div> <div class='range'> <fieldset class='flex three center'> <label style='text-align:right;'><span class='label normal' >小时</span></label> <label><input id='hueh' type='range' name='hue_value' min='0' max='360' step='1' oninput='sendHue(\"h\");' /></label>  <label><input id='hueh_value' name='hue_value' type='text' style='border: 0;' value='180'/> </label> </fieldset> </div> <div class='range'> <fieldset class='flex three center'> <label style='text-align:right;'><span class='label normal' >分钟</span></label> <label><input id='huem' type='range' name='hue_value' min='0' max='360' step='1' oninput='sendHue(\"m\");' /></label>  <label><input id='huem_value' name='hue_value' type='text' style='border: 0;' value='180'/> </label> </fieldset> </div> <div class='range'> <fieldset class='flex three center'> <label style='text-align:right;'><span class='label normal' >秒钟</span></label> <label><input id='hues' type='range' name='hue_value' min='0' max='360' step='1' oninput='sendHue(\"s\");' /></label>  <label><input id='hues_value' name='hue_value' type='text' style='border: 0;' value='180'/> </label> </fieldset> </div> <div class='range'> <fieldset class='flex three center'> <label style='text-align:right;'><span class='label normal' >星期</span></label> <label><input id='huew' type='range' name='hue_value' min='0' max='360' step='1' oninput='sendHue(\"w\");' /></label>  <label><input id='huew_value' name='hue_value' type='text' style='border: 0;' value='180'/> </label> </fieldset> </div> <br><br> <script> function sendBrightness() {  var Obrightness = document.getElementById('bt').value;  var oMessage = 's';  if (Obrightness.length == 1) {  oMessage = oMessage + '00';  } else if (Obrightness.length == 2) {  oMessage = oMessage + '0';  }  document.getElementById('bt_value').value=parseInt(Obrightness ? Obrightness : 999); oMessage = oMessage + parseInt(Obrightness ? Obrightness : 999);  console.log('oMessage: ' + oMessage); connection.send(oMessage);  } function sendHue(n) {  var OHueValue = document.getElementById('hue'+n).value;  var oMessage = 'h'+n;  if (OHueValue.length == 1) {  oMessage = oMessage + '00';  } else if (OHueValue.length == 2) {  oMessage = oMessage + '0';  }  if(n=='a'){ var els =document.getElementsByName('hue_value'); for (var i = 0, j = els.length; i < j; i++){ els[i].value = OHueValue; } }else{ document.getElementById('hue'+n+'_value').value=parseInt(OHueValue ? OHueValue : 360); } oMessage = oMessage + parseInt(OHueValue ? OHueValue : 999);  console.log('oMessage: ' + oMessage); connection.send(oMessage);  } function configSave() { var oMessage = 'c';  console.log('oMessage: ' + oMessage); connection.send(oMessage);  } </script> <div class='flex two center'> <label> <button class='success' onclick='configSave()' style='font-size: 2.5em;right: 0px;'>保存配置</button> </label> <label > <label for='tab-1' class='button normal' style='font-size: 2.5em;'>返回主页</label> </label> </div>  </div> <div> <h1 class='flex center'>时钟风格</h1> <div style='height: 800px;'> <h1 class='flex one'> <label> <input type='radio' onclick='clickRad(1);' name='radio-clock'> <span class='checkable'>HH:mm:ss</span> </label> <br><br> <label> <input type='radio' onclick='clickRad(2);' name='radio-clock'> <span class='checkable'>HH:mm</span> </label> <br><br> <label> <input type='radio' onclick='clickRad(3);' name='radio-clock'> <span class='checkable'>emoji HH:mm</span> </label> <br><br> <label> <input type='radio' onclick='clickRad(4);' name='radio-clock'> <span class='checkable'>emoji HH:mm</span> </label> </h1> <h1 class='flex center'>日期风格</h1> <h1 class='flex one'> <label> <input type='radio' onclick='DateModel(1);' name='radio-date'> <span class='checkable'>MM.DD</span> </label> <br><br> <label> <input type='radio' onclick='DateModel(2);' name='radio-date'> <span class='checkable'>emoji MM.DD</span> </label> <br><br> </h1> </div> <script> function clickRad(num) {  var styleNum = 't' + parseInt(num).toString(16);  console.log('Style: ' + styleNum);  connection.send(styleNum); } function DateModel(num) {  var styleNum = 'd' + parseInt(num).toString(16);  console.log('Style: ' + styleNum);  connection.send(styleNum); } </script> <div class='flex one'> <label > <label for='tab-1' class='button normal' style='font-size: 2.5em;'>返回主页</label> </label> </div> </div>  </div> </div></body></html>");
    Serial.println("index.html sent.");
  });
  server.begin();

  // start webSocket server
  webSocket.begin();
  webSocket.onEvent(webSocketEvent);
  // Add service to MDNS
  MDNS.addService("http", "tcp", 80);
  MDNS.addService("ws", "tcp", 81);
}

void WebServer_run(){
  MDNS.update();
  webSocket.loop();
  server.handleClient();  
}

/*******************************************************
 * 函数名：webSocketEvent
 * 描述  ：处理网页webSocket数据，事件回调函数
 * 参数  ：
 *         @num
 *         @type
 *         @payload
 *         @length
 * 返回值：无
 **********************************************************/
void webSocketEvent(uint8_t num, WStype_t type, uint8_t *payload, size_t length)
{
    switch (type)
    {
    case WStype_DISCONNECTED:
        Serial.printf("[%u] Disconnected!\n", num);
        break;
    case WStype_CONNECTED:
    {
        IPAddress ip = webSocket.remoteIP(num);
        Serial.printf("[%u] Connected from %d.%d.%d.%d url: %s\n", num, ip[0], ip[1], ip[2], ip[3], payload);
        webSocket.sendTXT(num, "Connected"); // send message to client
        configSync(num); // 配置同步
    }
    break;
    case WStype_TEXT:
    {
        Serial.printf("[%u] get Text: %s\n", num, payload);
        if(((char *)payload)[0] == '{'||((char *)payload)[0] == 's') 
        {
          strcpy(settingMessage,(char *)payload);
          if (settingMessage[0] == 's')//亮度
          {
             int bt= ((int)settingMessage[1]-48)*100+((int)settingMessage[2]-48)*10+(int)settingMessage[3]-48;
             if(bt>=0&&bt<=255) brightnessNow = bt;
             matrix.setBrightness(brightnessNow);
             matrix.show();
          }
          else if(settingMessage[0] == '{')
          {
             //handleSettingMessage();
          }
        }
        else if (((char *)payload)[0] != 'C') 
        {
          strcpy(socketMessage, (char *)payload);
          if (socketMessage[0] == 'p')
          {
              matrix.clear();
              pic_x = ((int)socketMessage[2]) - 47;
              pic_y = ((int)socketMessage[1]) - 47;
              SetEmoji(pic_x, pic_y);
              matrix.show();
          }
          else if (socketMessage[0] == 'F')//显示固件信息
          {
              showFirmwareInfo(3, 1, true);
              delay(500);
              showFirmwareInfoEnd();
          }
          else if (socketMessage[0] == 't')//时钟风格
          {
              int cm = (int)socketMessage[1]-48;
              matrix.clear();
              clockMode = cm<5? cm:1;
          }
          else if (socketMessage[0] == 'd')//日期风格
          {
              int dm = (int)socketMessage[1]-48;
              matrix.clear();
              dateMode = dm<3? dm:1;
          }
          else if(socketMessage[0] == 'm')//模式变更
          {
            if(socketMessage[1] == 'c'){
              modeChange();//模式切换
              configSync(num); // 配置同步
            }else{
              int m = (int)socketMessage[1]-48;
              if(m<MODE_MAX+1 && m>-1){
                Mode = m;
                Serial.print("web切换模式：");
                Serial.println(m);
                matrix.clear();
                switchMode(true,Mode);
              }
            } 
          }else if(socketMessage[0] == 'h'){//颜色设置
                int hh= ((int)socketMessage[2]-48)*100+((int)socketMessage[3]-48)*10+(int)socketMessage[4]-48;
                Serial.print("传入色值：");
                Serial.println(hh);
                if(hh>=0&&hh<=360){  
                    switch (socketMessage[1])
                    {
                    case 'a':
                        hue = hh;
                        hueh = hh;
                        huem = hh;
                        hues = hh;
                        huew = hh;
                        break;
                    case 'd':
                        hue = hh;
                        break;
                    case 'h':
                        hueh = hh;
                        break;
                    case 'm':
                        huem = hh;
                        break;
                    case 's':
                        hues = hh;
                        break;   
                    case 'w':
                        huew = hh;
                        break;              
                    default:
                        break;
                    }
                }
          }else if(socketMessage[0] == 'c'){
              configSave();
          }
        }
    }
    break;
    }
}
